package cn.zmwh.im.server.netty.processor;

import cn.hutool.json.JSONUtil;
import cn.zmwh.im.common.pojo.dto.IMRecvInfo;
import cn.zmwh.im.common.pojo.dto.IMUserInfo;
import cn.zmwh.im.common.pojo.dto.transfer.MessagePrivate;
import cn.zmwh.im.server.config.HintManager;
import cn.zmwh.im.server.constant.BsKImConstant;
import cn.zmwh.im.server.constant.IMCmdConstants;
import cn.zmwh.im.server.constant.IMRedisKey;
import cn.zmwh.im.server.modules.message.pojo.entity.ImMessage;
import cn.zmwh.im.server.modules.message.service.ImMessageService;
import cn.zmwh.im.server.modules.ums.pojo.entity.ImUser;
import cn.zmwh.im.server.modules.ums.service.ImUserService;
import cn.zmwh.im.server.mq.dto.IMInfo;
import cn.zmwh.im.server.netty.MessageService;
import cn.zmwh.im.server.netty.UserChannelMap;
import cn.zmwh.im.server.utils.IdGenerator;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

@Slf4j
@RequiredArgsConstructor
@Component("systemProcessor")
public class MessageProcessorSystem implements ImMessageProcessor {

    private final RedisTemplate redisTemplate;
    private final MessageService messageService;
    private final ImMessageService imMessageService;
    private final ImUserService imUserService;

    public IMInfo read(ChannelHandlerContext ctx, IMInfo sendInfo) {
        Channel channel = ctx.channel();
        AttributeKey<Long> userIdAttr = AttributeKey.valueOf(BsKImConstant.CHANNEL_ATTR_KEY.USER_ID);
        Long sendId = channel.attr(userIdAttr).get();
        if (sendId == null) {
            IMInfo<Object> result = new IMInfo<>();
            result.setCmd(IMCmdConstants.FORCE_LOGOUT);
            result.setData("未登录");
            return result;
        }
        AttributeKey<String> terminalAttr = AttributeKey.valueOf(BsKImConstant.CHANNEL_ATTR_KEY.TERMINAL_TYPE);
        String terminal = channel.attr(terminalAttr).get();
        //String sendKey = StrUtil.join(":", IMRedisKey.GAIN_SERVER_ID, sendId, terminal);

        MessagePrivate messagePrivate = JSONUtil.toBean(JSONUtil.toJsonStr(sendInfo.getData()), MessagePrivate.class);
        String messageId = IdGenerator.nextIdStr();
        Long receiverId = messagePrivate.getRecvId();//todo 判断好友是否存在


        messagePrivate.setMessageId(messageId);
        messagePrivate.setSendId(sendId);
        messagePrivate.setSendTime(new Date());
        IMInfo<Object> result = new IMInfo<>();
        result.setCmd(IMCmdConstants.SYSTEM_MESSAGE);
        result.setData(messagePrivate);
        result.setMessageId(messageId);

        ImMessage imMessage = new ImMessage();
        imMessage.setUid(sendId);
        imMessage.setSendId(-1L);//系统消息发送方为-1
        imMessage.setMessageId(messageId);
        imMessage.setRecvId(receiverId);
        imMessage.setContent(messagePrivate.getContent());
        imMessage.setSendTime(messagePrivate.getSendTime());
        imMessage.setType(messagePrivate.getType());

        messageService.messageSendPrivate(imMessage, IMRedisKey.IM_MESSAGE_SYSTEM_QUEUE, receiverId, new IMUserInfo(sendId, terminal), true);


//        Map<String, IMUserInfo> receiverMap = new HashMap<>();
//        IMTerminalType[] values = IMTerminalType.values();
//        for (IMTerminalType value : values) {
//            String terminalV = value.terminal();
//            String key = StrUtil.join(":", IMRedisKey.GAIN_SERVER_ID, receiverId, terminalV);
//            receiverMap.put(key, new IMUserInfo(receiverId, terminalV));
//        }
//        List<ImMessage> list = new ArrayList<>();
//        messagePrivate.setStatus(15);
//        List<Object> serverIds = redisTemplate.opsForValue().multiGet(receiverMap.keySet());
//        Map<String, List<IMUserInfo>> map = new HashMap<>();
//        int index = 0;
//        for (Map.Entry<String, IMUserInfo> entry : receiverMap.entrySet()) {
//            Object serverId = serverIds.get(index++);//index++后置递增， ++index前置递增
//            if (serverId == null) {
//                continue;
//            }
//            IMUserInfo value = entry.getValue();
//            String serverIdStr = serverId.toString();
//            map.computeIfAbsent(serverIdStr, k -> new ArrayList<>()).add(value);//根据服务分组
//        }
//        ImMessage recvImMessage = new ImMessage();
//        BeanUtil.copyProperties(imMessage, recvImMessage);
//        recvImMessage.setUid(receiverId);
//        if (CollUtil.isNotEmpty(map)) {//好友存在在线终端
//            IMRecvInfo imRecvInfo = new IMRecvInfo();
//            imRecvInfo.setCmd(IMCmdConstants.SYSTEM_MESSAGE);
//            imRecvInfo.setData(messagePrivate);
//            imRecvInfo.setMessageId(messageId);
//            imRecvInfo.setSender(new IMUserInfo(sendId, terminal));
//            Set<Map.Entry<String, List<IMUserInfo>>> entries = map.entrySet();
//            for (Map.Entry<String, List<IMUserInfo>> entry : entries) {
//                String key = entry.getKey();
//                List<IMUserInfo> value = entry.getValue();
//                imRecvInfo.setReceivers(value);
//                String queueKey = String.join(":", IMRedisKey.IM_MESSAGE_SYSTEM_QUEUE, key);
//                redisTemplate.opsForList().rightPush(queueKey, imRecvInfo);
//            }
//            recvImMessage.setStatus(1);//接收消息是待推送
//            messagePrivate.setStatus(1);//发送消息是已投递
//        } else {
//            recvImMessage.setStatus(5);//不存在在现在终端，直接等待重连时候推送离线消息
//        }
//        list.add(recvImMessage);
//
//        imMessage.setStatus(messagePrivate.getStatus());
//        list.add(imMessage);
//
//        try (HintManager hintManager = HintManager.getInstance()) {
//            Set<Long> userIds = list.stream().map(ImMessage::getUid).collect(Collectors.toSet());
//            Set<MessageDB> messageDBS = imUserService.qryMessageDb(userIds);
//            for (MessageDB messageDB : messageDBS) {
//                Integer messageDb = messageDB.getDb();
//                Integer messageTable = messageDB.getTable();
//                Set<Long> itemUserIds = messageDB.getUserIds();
//                List<ImMessage> itemList = list.stream().filter(item -> itemUserIds.contains(item.getUid())).collect(Collectors.toList());
//                hintManager.addDbValue(BsKImConstant.DbName.IM_MESSAGE, messageDb);
//                hintManager.addTableValue(messageTable);
//                imMessageService.saveBatch(itemList);
//            }
//        }


        return result;
    }

    @Override
    public void send(IMRecvInfo recvInfo) {
        IMUserInfo sender = recvInfo.getSender();
        String messageId = recvInfo.getMessageId();
        List<IMUserInfo> receivers = recvInfo.getReceivers();

        try (HintManager hintManager = HintManager.getInstance()) {
            for (IMUserInfo receiver : receivers) {
                log.info("接收到私聊消息，发送者:{},接收者:{}，内容:{}", sender.getId(), receiver.getId(), recvInfo.getData());
                try {
                    Long uid = receiver.getId();
                    Channel channel = UserChannelMap.getChannel(uid, receiver.getTerminal());
                    if (channel == null) {
                        log.error("未找到channel，发送者:{},接收者:{}，内容:{}", sender.getId(), receiver.getId(), recvInfo.getData());
                        continue;
                    }
                    // 推送消息到用户
                    IMInfo<Object> sendInfo = new IMInfo<>();
                    sendInfo.setMessageId(messageId);
                    sendInfo.setWantAck(true);
                    sendInfo.setCmd(IMCmdConstants.SYSTEM_MESSAGE);
                    sendInfo.setData(recvInfo.getData());
                    channel.writeAndFlush(sendInfo);

                    ImUser user = imUserService.getById(uid);
                    hintManager.addDbValue(BsKImConstant.DbName.IM_MESSAGE, user.getMessageDb());
                    hintManager.addTableValue(user.getMessageTable());
                    imMessageService.update(Wrappers.<ImMessage>lambdaUpdate()
                            .set(ImMessage::getStatus, 10)
                            .eq(ImMessage::getUid, uid)
                            .ne(ImMessage::getStatus, 15)
                            .eq(ImMessage::getMessageId, messageId));
                    hintManager.close();
                } catch (Exception e) {
                    // 消息推送失败确认
                    log.error("发送异常，发送者:{},接收者:{}，内容:{}", sender.getId(), receiver.getId(), recvInfo.getData(), e);
                }
            }
        }
    }


    @Override
    public void ack(Long uid, String messageId, Object data) {
        log.info("收到消息确认，用户id:{},消息id:{}", uid, messageId);
        ImUser byId = imUserService.getById(uid);

        try (HintManager hintManager = HintManager.getInstance()) {
            Integer messageDb = byId.getMessageDb();
            Integer messageTable = byId.getMessageTable();
            hintManager.addDbValue(BsKImConstant.DbName.IM_MESSAGE, messageDb);
            hintManager.addTableValue(messageTable);
            ImMessage one = imMessageService.getOne(Wrappers.<ImMessage>lambdaQuery()
                    .eq(ImMessage::getUid, uid)
                    .eq(ImMessage::getMessageId, messageId));
            if (one == null) {
                return;
            }
            Integer status = one.getStatus();
            if (status.equals(15)) {
                return;
            }
            one.setStatus(15);
            imMessageService.updateById(one);
            //系统消息，发送方为平台则没有发送方则不更新发送方
        }
    }

}
